#include <sum_btimer.h>
#include <sum_csr.h>
#include <sum_dma.h>
#include <sum_eclic.h>
#include <sum_gpio.h>
#include <sum_rcu.h>
#include <sum_usart.h>
#include <sum_wfi.h>
#include <sys_mem.h>
#include <util_trans.h>

#define AHB_FREQ_DEFAULT 8000000
#define APB2_FREQ_DEFAULT 8000000
#define BTIMER_GAP (AHB_FREQ_DEFAULT >> 2)

// RCU中将GPIOA、USART0、DMA0上电。
static void _setup_rcu(void) {
	rcu_apb2_s apb2 = {
		.apb2_0_7.GPIOA = 1,
		.apb2_8_15.USART0 = 1,
	};
	rcu_apb2_en_di(apb2);

	rcu_ahb_0_7_s ahb_0_7 = {
		.DMA0 = 1,
		.FMCSP = 1,
		.SRAMSP = 1,
	};
	rcu_ahb_0_7_en_di(ahb_0_7);
}

// 配置A9为AF输出，A10为浮空输入。
static void _setup_gpafio(void) {
	gpio_ctl_8_15_s ctl = {
		// A9的配置：低速输出、AF、推挽
		.pin9_ctl = GPIO_OUT_AF_PP_2MHZ,
		// A10的配置：输入、浮空
		.pin10_ctl = GPIO_IN_FLOAT,
	};
	gpio_setup_pin_8_15(GPIOA_Q, ctl);
}

// 使能USART0本身，以及其发送功能。
static void _setup_usart0(void) {
	usart_ctl2_expl_s ctl2 = {
		.dma_trans_en = 1,
	};
	usart_setup_2(USART0_Q, ctl2);

	usart_ctl0_expl_s ctl0 = {
		.trans_en = 1,
		.usart_en = 1,
	};
	usart_setup_0(USART0_Q, ctl0);
}

// DMA0发送
static void _dma0_send(void) {
	// 该字符串在flash中，也可以使用DMA。
	__attribute__((aligned(4))) static const volatile u8_s str_a[] =
		"Printed by DMA!\n";
	// 先关闭该DMA通道
	dma_chxctl_expl_s ch_usart0_ctl_tmp = {
		.channel_en = 0,
	};
	// 配置该DMA通道
	dma_setup_channel_ctl(DMA0_Q, DMA_CH3_R, ch_usart0_ctl_tmp);
	u32_s usart_data_q = usart_get_data_q(USART0_Q);
	dma_wreg_chxpaddr(DMA0_Q, DMA_CH3_R, usart_data_q);
	dma_wreg_chxmaddr(DMA0_Q, DMA_CH3_R, (u32_s)str_a);
	dma_wreg_chxcnt(DMA0_Q, DMA_CH3_R, sizeof(str_a) - sizeof(u8_s));
	// 开启通道
	dma_chxctl_expl_s ch_usart0_ctl = {
		.channel_en = 1,
		.direction = DMA_DIR_MEM_TO_PHRI,
		.circular_mode_en = 0,
		.phri_next_addr_algorithm = DMA_NAGA_FIX,
		.phri_data_width = DMA_WIDTH_32_BITS,
		.mem_next_addr_algorithm = DMA_NAGA_INCREASE,
		.mem_data_width = DMA_WIDTH_8_BITS,
		.mem_to_mem_mode_en = 0,
		.priority = 1,
	};
	dma_setup_channel_ctl(DMA0_Q, DMA_CH3_R, ch_usart0_ctl);
}

// 定时中断
static void _btimer_irq(void) {
	btimer_refresh(BTIMER_GAP);
	_dma0_send();
}

// 中断配置
static void _setup_interrupt(void) {
	// 中断入口地址设为自带的中断入口
	csr_set_default_exti_entry();
	// 中断向量表
	static const __attribute__((aligned(512))) eclic_irqvec_t ivt = {
		.irq_entry_fa[IRQNO_BTIMER] = _btimer_irq,
	};
	eclic_set_ivt_base(&ivt);
	// 设置中断level和priority，其中priority域占据全部bit，无level。
	eclic_set_level_priority_bit_amount(NLBITS_LEVEL_0_PRIORITY_4);
	eclic_clicint_expl_s clicint = {
		.inter_en.value = 1,
		.attr.vector_mode = 0,
		.level_priority = eclic_set_level_priority(
			NLBITS_LEVEL_0_PRIORITY_4, 0, 0),
	};
	eclic_setup_inter_expl(IRQNO_BTIMER, clicint);
	// 打开全局中断
	csr_enable_global_interrupt();
}

__attribute__((noreturn, section(".MAIN"))) void user_main(void) {
	mem_scatter_load();

	_setup_rcu();
	_setup_gpafio();
	usart_set_baud_rate(USART0_Q, 115200, APB2_FREQ_DEFAULT);
	_setup_usart0();

	// 异常入口地址直接设为0（理论上该例程中不可能发生异常）。
	csr_enable_eclic_set_entry(0);
	// 中断配置
	_setup_interrupt();

	btimer_start(BTIMER_GAP);
	while (1) {
		wfi();
	}
}
